﻿
namespace Octopus.OctopusLib

open System.Management



type HostNodeWindowsCounters (hostName:string, domain:string, username:string, password:string) =
  let _username =
    if username = null then null
    else if domain = null then username
    else (domain + "\\" + username)
  let _password =
    if _username = null then null
    else password

  let computerSystem =
    let w = Utility.get_cimv2_WmiObject_auth hostName "SELECT * FROM Win32_ComputerSystem" _username _password
    if w <> null then w
    else failwith ("Unable to communicate with " + hostName)

  let perfFormattedData_PerfOS_Memory =
    let w = Utility.get_cimv2_WmiObject_auth hostName "SELECT * FROM Win32_PerfFormattedData_PerfOS_Memory" _username _password
    if w <> null then w
    else failwith ("Unable to communicate with " + hostName)

  let perfFormattedData_PerfOS_Processor_Total =
    let ww = Utility.get_cimv2_WmiObjects_auth hostName "SELECT * FROM Win32_PerfFormattedData_PerfOS_Processor" _username _password
    if ww = null || ww.Length = 0 then failwith ("Unable to communicate with " + hostName)
    else if ww.Length = 1 then ww.[0]
    else
      let w1 = ww |> Array.filter (fun x -> x.["Name"].Equals("_Total"))
      w1.[0]
  
  new (hostName:string) =
    new HostNodeWindowsCounters(hostName,null,null,null)

  interface System.IDisposable with
    member x.Dispose () =
      computerSystem.Dispose()
      perfFormattedData_PerfOS_Memory.Dispose()
      perfFormattedData_PerfOS_Processor_Total.Dispose()
  
  member x.Name with get() = computerSystem.["Name"].ToString()

  member x.CpuCount = computerSystem.["NumberOfLogicalProcessors"] :?> uint32
  member x.MemorySize = computerSystem.["TotalPhysicalMemory"] :?> uint64
  member x.CpuLoad = float32 ( perfFormattedData_PerfOS_Processor_Total.["PercentProcessorTime"] :?> uint64 )
  member x.MemoryFree = perfFormattedData_PerfOS_Memory.["AvailableBytes"] :?> uint64
(*
AdminPasswordStatus = 3
AutomaticManagedPagefile = True
AutomaticResetBootOption = True
AutomaticResetCapability = True
BootOptionOnLimit = null
BootOptionOnWatchDog = null
BootROMSupported = True
BootupState = Normal boot
Caption = REALNODE01
ChassisBootupState = 2
CreationClassName = Win32_ComputerSystem
CurrentTimeZone = 120
DaylightInEffect = True
Description = AT/AT COMPATIBLE
DNSHostName = REALNODE01
Domain = ferrari.local
DomainRole = 3
EnableDaylightSavingsTime = True
FrontPanelResetStatus = 3
InfraredSupported = False
InitialLoadInfo = null
InstallDate = null
KeyboardPasswordStatus = 3
LastLoadInfo = null
Manufacturer = HP
Model = ProLiant BL465c G1  
Name = REALNODE01
NameFormat = null
NetworkServerModeEnabled = True
NumberOfLogicalProcessors = 4
NumberOfProcessors = 2
OEMLogoBitmap = null
OEMStringArray = System.String[]
PartOfDomain = True
PauseAfterReset = -1
PCSystemType = 0
PowerManagementCapabilities = null
PowerManagementSupported = null
PowerOnPasswordStatus = 3
PowerState = 0
PowerSupplyState = 2
PrimaryOwnerContact = null
PrimaryOwnerName = Windows User
ResetCapability = 1
ResetCount = -1
ResetLimit = -1
Roles = System.String[]
Status = OK
SupportContactDescription = null
SystemStartupDelay = null
SystemStartupOptions = null
SystemStartupSetting = null
SystemType = x64-based PC
ThermalState = 2
TotalPhysicalMemory = 4292788224
UserName = null
WakeUpType = 6
Workgroup = null
*)


type HyperVNode (id:int, hostName:string, ipAddress:string, externalNic:System.Guid, cpuCount:uint16, memorySize:uint64, isReachable:bool, lastCpuLoad:float32, lastMemoryFree:uint64, lastCounterUpdated:System.DateTime) =

  member x.ID = id
  member x.HostName = hostName
  member x.IpAddress = ipAddress
  member x.ExternalNIC_Guid = externalNic
  member x.CpuCount = cpuCount
  member x.MemorySize = memorySize
  member x.IsReachable = isReachable
  member x.LastCpuLoad = lastCpuLoad
  member x.LastMemoryFree = lastMemoryFree
  member x.LastCounterUpdated = lastCounterUpdated
  
  override x.ToString() = hostName

  // for debug purpose only - it's not reliable too, so DELETE IT as soon as possibile
  member x.Serialize () =
      let res = [| x.ID.ToString(); x.HostName; x.IpAddress; string x.ExternalNIC_Guid;x.CpuCount.ToString();
                   x.MemorySize.ToString(); x.IsReachable.ToString(); x.LastCpuLoad.ToString();
                   x.LastMemoryFree.ToString(); x.LastCounterUpdated.ToFileTimeUtc().ToString() |]
      Utility.ObjSerializer.serialize res

  // for debug purpose only - it's not reliable too, so DELETE IT as soon as possibile
  static member Deserialize (str:string) =
      let res = (Utility.ObjSerializer.deserialize str) :?> string array
      let id = System.Int32.Parse( res.[0] )
      let hostName = res.[1]
      let ipAddress = res.[2]
      let externalNic = new System.Guid(res.[3])
      let cpucount = System.UInt16.Parse( res.[4] )
      let memorysize = System.UInt64.Parse( res.[5] )
      let isreachable = System.Boolean.Parse( res.[6] )
      let lastcpuload = System.Single.Parse( res.[7] )
      let lastmemoryfree = System.UInt64.Parse( res.[8] )
      let lastcounterupdated = System.DateTime.FromFileTimeUtc( System.Int64.Parse( res.[9] ) )
      new HyperVNode(id, hostName, ipAddress, externalNic, cpucount, memorysize, isreachable, lastcpuload, lastmemoryfree, lastcounterupdated)